package com.mimiwang.common.utils;

import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.exception.GeoIp2Exception;
import com.maxmind.geoip2.model.CityResponse;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.http.HttpRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @AUTHOR:游李滨
 * @DATE:2023/6/27 14:48
 */
public class IPUtil {


    private static DatabaseReader reader;
    static {
        ApplicationHome applicationHome = new ApplicationHome(IPUtil.class);
        String classpath = applicationHome.getSource().toString();


        String path=classpath+"/GeoLite2-City.mmdb";
        File file = new File(path);
        try {
            reader=new DatabaseReader.Builder(file).build();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static class Address{
        private String country;
        private String province;
        private String city;
//        经度
        private double longitude;
//        纬度
        private double latitude;

        public Address() {
        }

        public Address(String country, String province, String city, double longitude, double latitude) {
            this.country = country;
            this.province = province;
            this.city = city;
            this.longitude = longitude;
            this.latitude = latitude;
        }

        public String getCountry() {
            return country;
        }

        public void setCountry(String country) {
            this.country = country;
        }

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public double getLongitude() {
            return longitude;
        }

        public void setLongitude(double longitude) {
            this.longitude = longitude;
        }

        public double getLatitude() {
            return latitude;
        }

        public void setLatitude(double latitude) {
            this.latitude = latitude;
        }
    }
    public static CityResponse getCityResponse(HttpServletRequest request) throws IOException, GeoIp2Exception {
        String ipAddr = getIpAddr(request);
        return reader.city(InetAddress.getByName(ipAddr));
    }
    public static CityResponse getCityResponse(String ip) throws IOException, GeoIp2Exception {
        return reader.city(InetAddress.getByName(ip));
    }

    public static Address getAddress(HttpServletRequest request) throws IOException, GeoIp2Exception {
        String ip = getIpAddr(request);
        return getAddress(ip);
    }
    public static Address getAddress(String ip) throws IOException, GeoIp2Exception {
        CityResponse info = reader.city(InetAddress.getByName(ip));
        String country = info.getCountry().getNames().get("zh-CN");
        String province = info.getMostSpecificSubdivision().getNames().get("zh-CN");
        String city = info.getCity().getNames().get("zh-CN");
        Double longitude = info.getLocation().getLongitude();
        Double latitude = info.getLocation().getLatitude();
        return new Address(country,province,city,longitude,latitude);
    }
    /**
     *
     * @description: 获得国家
     * @param
     * @param ip ip地址
     * @return
     * @throws Exception
     */
    public static String getCountry(String ip) throws Exception {
        return reader.city(InetAddress.getByName(ip)).getCountry().getNames().get("zh-CN");
    }

    /**
     *
     * @description: 获得省份
     * @param
     * @param ip ip地址
     * @return
     * @throws Exception
     */
    public static String getProvince(String ip) throws Exception {
        return reader.city(InetAddress.getByName(ip)).getMostSpecificSubdivision().getNames().get("zh-CN");
    }

    /**
     *
     * @description: 获得城市
     * @param
     * @param ip ip地址
     * @return
     * @throws Exception
     */
    public static String getCity(String ip) throws Exception {
        return reader.city(InetAddress.getByName(ip)).getCity().getNames().get("zh-CN");
    }

    /**
     *
     * @description: 获得经度
     * @param
     * @param ip ip地址
     * @return
     * @throws Exception
     */
    public static Double getLongitude(String ip) throws Exception {
        return reader.city(InetAddress.getByName(ip)).getLocation().getLongitude();
    }

    /**
     *
     * @description: 获得纬度
     * @param
     * @param ip ip地址
     * @return
     * @throws Exception
     */
    public static Double getLatitude( String ip) throws Exception {
        return reader.city(InetAddress.getByName(ip)).getLocation().getLatitude();
    }



    private static final String UNKNOWN = "unknown";

    protected IPUtil(){ }

    /**
     * 获取 IP地址
     * 使用 Nginx等反向代理软件， 则不能通过 request.getRemoteAddr()获取 IP地址
     * 如果使用了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP地址，
     * X-Forwarded-For中第一个非 unknown的有效IP字符串，则为真实IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }
    public static String getAddrByIp2Region(HttpServletRequest request){
        return getAddrByIp2Region(getIpAddr(request));
    }

    public static  String getAddrByIp2Region(String ip){
        String dbPath = "/ip2region.xdb";
        ApplicationHome ah = new ApplicationHome(IPUtil.class);
        String docStorePath = ah.getSource().toString();
        System.out.println(docStorePath);
        dbPath=docStorePath+dbPath;


        // 1、从 dbPath 加载整个 xdb 到内存。
        byte[] cBuff;
        try {
            cBuff = Searcher.loadContentFromFile(dbPath);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
        Searcher searcher;
        try {
            searcher = Searcher.newWithBuffer(cBuff);
        } catch (Exception e) {

            return null;
        }
        // 3、查询
        try {
            String region = searcher.searchByStr(ip);
            return region;
        } catch (Exception e) {
           e.printStackTrace();
        }
        return null;
    }

}
